﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.ApplicationInsights.AspNetCore.Extensions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Filters;
using ZilLion.Core.Unities.UnitiesMethods;
using ZilLion.Service.Core.ConfigManager.Manager;
using ZilLion.Service.Core.Log;
using QueryString = ZilLion.Service.Core.Unities.ExtensionMethods.QueryString;

namespace ZilLion.Service.Core.Infrastructure.Filters
{
    public class JwtTokenFilter : ActionFilterAttribute
    {
        public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            return Task.Run(() =>
            {
                var allowAnonymous = context.Filters.Any(item => item is IAllowAnonymousFilter);
                if (!allowAnonymous)
                {
                    var queryString =
                        QueryString.Parse(context.HttpContext.Request.QueryString.ToString()
                            .Replace("?", string.Empty));
                    queryString.TryGetValue("token", out var token);
                    IDictionary<string, dynamic> jwtTokenDic = null;
                    if (token.IsNullOrEmpty()) //获取不到Token 验证不通过
                    {
                        
                        if (!(context.HttpContext.Request.GetUri().ToString().ToLower().Contains("jwt/getjwt") || context.HttpContext.Request.GetUri().ToString().ToLower().Contains("swagger") ||
                              context.HttpContext.Request.GetUri().ToString().ToLower().Contains("img/get")))
                        {
                            context.HttpContext.Response.StatusCode = 401;
                            context.HttpContext.Response.WriteAsync("Token为空", Encoding.UTF8);
                        }
                        else
                        {
                            next();
                        }
                    }
                    else
                    {
                        try
                        {
                            jwtTokenDic = JwtTokenUtility.DecodeJwtToken(token,
                                ZilLionConfigurationManager.GetConfigInstance<WebApiAppConfig>().JwtSecretKey);
                        }
                        catch (Exception e)
                        {
                            ZilLionLogManager.Instance().Error(e);
                            context.HttpContext.Response.StatusCode = 401;
                            context.HttpContext.Response.WriteAsync("解析jwt时发生未知错误", Encoding.UTF8);
                            return;
                        }
                        if (jwtTokenDic != null && jwtTokenDic.Any())
                        {
#if !DEBUG
                        long exp = 0;
                        if (jwtTokenDic.ContainsKey("exp"))
                            exp = jwtTokenDic["exp"];

                        var nowutc = Math.Round(
                            (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc))
                            .TotalSeconds
                        ).ToLongOrDefault();
                        var isExpire = nowutc > exp + 120; //+120s的原因是防止网络延迟  在客户端token没过期，到服务端加上网络延迟已经过期
                        if (isExpire) //token过期
                        {
                          context.HttpContext.Response.StatusCode = 401;
                            context.HttpContext.Response.WriteAsync("jwt已过期", Encoding.UTF8);
                            context.Result.ExecuteResultAsync(context);
                        }


#endif
                            //把Token解码出来的信息加入actioncontext，方便后面管道filer 使用

                            var jwtInfoContainer =
                                (JwtInfoContainer) context.HttpContext.RequestServices.GetService(
                                    typeof(JwtInfoContainer));

                            if (jwtInfoContainer?.JwtInfoDictionary != null)
                                foreach (var info in jwtTokenDic)
                                    if (!jwtInfoContainer.JwtInfoDictionary.ContainsKey("currentjwt" + info.Key))
                                        jwtInfoContainer.JwtInfoDictionary.TryAdd("currentjwt" + info.Key, info.Value);

                            next();
                        }
                        else
                        {
                            context.HttpContext.Response.StatusCode = 401;
                            context.HttpContext.Response.WriteAsync("解析jwt时发生未知错误", Encoding.UTF8);
                            context.Result.ExecuteResultAsync(context);
                        }
                    }
                }
                else
                {
                    next();
                }
            });
        }
    }
}